iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 5
0
AI & Data

看圖說故事,讓 Neo4j 重新詮釋你的資料庫系列 第 5

Neo4j 資料庫查詢語言 Cypher 第二部

  • 分享至 

  • xImage
  •  

Neo4j 看圖說故事 - 諾蘭執導的電影和演員們

Nolan Movies with Acters

在上一篇文章 Cypher(ㄧ) 中,我們學到了查詢資料庫,以及基本的新增 Node、Relation、Property 元素,這次來看看更多的語法。

問題一:新增 Node 前都得先確認是否存在嗎?

在前一篇文章,我們設定了情境:你想找諾蘭的電影,想先確認他是否存在資料庫中?沒有的話才新增。這真的是再常見不過的需求了!難道每次都得先 MATCH 後 CREATE ? 有沒有更方便的做法?有的!
MERGE = MATCH + CREATE

MERGE (nolan:Person {name: '諾蘭'})
RETURN nolan

MERGE 會先比對這筆資料是否已存在?沒有的話才新增,否則取既有的資料即可。除了讓語法更簡潔方便,也同時解決可能會重複新增 Node 的問題。

問題二:類似的資料或關係,只能不斷 Copy-Paste?

上次最後一個範例是,新增諾蘭的電影,並指定其導演關係,如下

CREATE (nolan:Person {name: '諾蘭'}),
(m1:Movie {title: '星際效應', released: 2014}),
(m2:Movie {title: '全面啟動', released: 2010}),
(m3:Movie {title: 'TENET天能', released: 2020}),
(nolan)-[:DIRECTED]->(m1),
(nolan)-[:DIRECTED]->(m2),
(nolan)-[:DIRECTED]->(m3)

但是他的電影很多啊!上面的語法只是新增其中三個,每次都要重複寫 Movie,有什麼方法可以更簡潔的輸入呢?接下來我們介紹 UNWIND
UNWIND 可以將陣列元素轉換成一筆一筆的資料列,我們將語法修改如下

UNWIND [
    {title: '追隨', released: 1998},
    {title: '記憶拼圖', released: 2000},
    {title: '針鋒相對', released: 2002},
    {title: '蝙蝠俠:開戰時刻', released: 2005},
    {title: '頂尖對決', released: 2006},
    {title: '黑暗騎士', released: 2008},
    {title: '全面啟動', released: 2010},
    {title: '黑暗騎士:黎明昇起', released: 2012},
    {title: '星際效應', released: 2014},
    {title: '敦克爾克大行動', released: 2017},
    {title: 'TENET天能', released: 2020}
] AS p
CREATE (m:Movie) SET m = p
RETURN m

這樣就可以新增諾蘭所有的電影

問題三:如何同時新增所有電影並指派關係?

上面的語法解決了一直輸入 Movie 的問題,但沒有建立導演關係,那我們把前兩個做法合併起來試試:

MERGE (nolan:Person {name: '諾蘭'})
UNWIND [
    {title: '追隨', released: 1998},
    {title: '記憶拼圖', released: 2000},
    {title: '針鋒相對', released: 2002},
    {title: '蝙蝠俠:開戰時刻', released: 2005},
    {title: '頂尖對決', released: 2006},
    {title: '黑暗騎士', released: 2008},
    {title: '全面啟動', released: 2010},
    {title: '黑暗騎士:黎明昇起', released: 2012},
    {title: '星際效應', released: 2014},
    {title: '敦克爾克大行動', released: 2017},
    {title: 'TENET天能', released: 2020}
] AS p
CREATE (m:Movie) SET m = p
CREATE (nolan)-[:DIRECTED]->(m)
RETURN nolan, m

WITH is required between MERGE and UNWIND (line 2, column 1 (offset: 34))
"UNWIND ["
^

會出現了如上的錯誤訊息,告訴我們 MERGE 和 UNWIND 之間必須有 WITH ,這是因為 Cypher 語言並不是 CRUD 讓你可以隨意排列組合操作的,必須有一定的順序,最常見的情境是:先查詢比對,後新增修改,這個是系統默認允許的隱性操作,不需要額外處理。
除了這樣的順序之外,其他都需要注意不能讓查詢和新增/刪除/修改同時操作,而是要視為各自獨立的區塊,用 WITH 來介接。
正確的寫法如下

MERGE (nolan:Person {name: '諾蘭'})
WITH nolan
UNWIND [
    {title: '追隨', released: 1998},
    {title: '記憶拼圖', released: 2000},
    {title: '針鋒相對', released: 2002},
    {title: '蝙蝠俠:開戰時刻', released: 2005},
    {title: '頂尖對決', released: 2006},
    {title: '黑暗騎士', released: 2008},
    {title: '全面啟動', released: 2010},
    {title: '黑暗騎士:黎明昇起', released: 2012},
    {title: '星際效應', released: 2014},
    {title: '敦克爾克大行動', released: 2017},
    {title: 'TENET天能', released: 2020}
] AS p
CREATE (m:Movie) SET m = p
CREATE (nolan)-[:DIRECTED]->(m)
RETURN nolan, m

談到了 UNWIND,也順便看看 FOREACH 的做法,如下

MERGE (nolan:Person {name: '諾蘭'})
WITH nolan, [
    {title: '追隨', released: 1998},
    {title: '記憶拼圖', released: 2000},
    {title: '針鋒相對', released: 2002},
    {title: '蝙蝠俠:開戰時刻', released: 2005},
    {title: '頂尖對決', released: 2006},
    {title: '黑暗騎士', released: 2008},
    {title: '全面啟動', released: 2010},
    {title: '黑暗騎士:黎明昇起', released: 2012},
    {title: '星際效應', released: 2014},
    {title: '敦克爾克大行動', released: 2017},
    {title: 'TENET天能', released: 2020}
] AS movies
FOREACH (p in movies | 
    CREATE (m:Movie) SET m = p
    CREATE (nolan)-[:DIRECTED]->(m)
)
RETURN nolan

FOREACH 與 UNWIND 不同的是,前者是純粹程式邏輯操作,而不是把資料展開,所以最後 RETURN 時無法回傳所有電影。
今天這一篇可能比較難懂,還是請讀者們自己也玩看看囉~ 歡迎與我討論


上一篇
Neo4j 資料庫查詢語言 Cypher 第一部
下一篇
Neo4j 資料庫查詢語言 Cypher 第三部
系列文
看圖說故事,讓 Neo4j 重新詮釋你的資料庫30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言